function states_ = gXbias_statelist(task, ptrs, useASL, showText)

if nargin < 1 || isempty(task)
    task = {'root'};
else
    task = {task};
end

if nargin < 2 || isempty(ptrs)
    ptrs = {'dXtc', 'dXquest', 'dXlr'};
end

if nargin < 3 || isempty(useASL)
    useASL = true;
end

if nargin < 4 || isempty(showText)
    showText = false;
end

% only wait for FP acquisition when using ASL
if useASL
    aqW = 3e4;
    aqJ = 'error';
else
    aqW = 0;
    aqJ = 'next';
end

% stimulus viewing time
show = 1000;
%show = 2000;

% wait-for-response time
post = 500;

% confirm-or-modify-response time
hang = 100;

% start central fixation or jump to self-adjustment mode
acquire = { ...
    'dXkbHID',  {'f', 'ASLLEFT', 'j', 'ASLRIGHT'}; ...
    'dXPMDHID', {9, 'ASLLEFT', 11, 'ASLRIGHT'}; ...
    'dXasl',    {[1,true,inf], 'hold', true}};

% hold central or rebound to acquire
hold = { ...
    'dXkbHID',  {'f', 'ASLLEFT', 'j', 'ASLRIGHT'}; ...
    'dXPMDHID', {9, 'ASLLEFT', 11, 'ASLRIGHT'}; ...
    'dXasl',    {[1,false,inf], 'acquire', true}};

% settle on tighter fixation or rebound to acquire
settle = { ...
    'dXkbHID',  {'any', 'error'}; ...
    'dXPMDHID', {'any', 'error'}; ...
    'dXasl',    {[2,false,inf], 'acquire', true}};

% maintain central fixation with hard restart
fixate = { ...
    'dXkbHID',  {'any', 'error'}; ...
    'dXPMDHID', {'any', 'error'}; ...
    'dXasl',    {[2,false,inf], 'error', true}};

% statelist options that make this task special
respond = { ...
    'dXkbHID',  {'j', 'right', 'f', 'left'}; ...
    'dXPMDHID', {11, 'right', 9, 'left'}; ...
    'dXasl',    {} ...
    };

% maintain fixation and pull left or right
left = { ...
    'dXkbHID',  {'j', 'both'}; ...
    'dXPMDHID',	{11, 'both'}; ...
    'dXasl',    {} ...
    };
right = { ...
    'dXkbHID',  {'f', 'both'}; ...
    'dXPMDHID',	{9, 'both'}; ...
    'dXasl',    {} ...
    };

% self-adjustment mode for showing suspicious eye position
ASLLEFT = { ...
    'dXkbHID',  {'j', 'ASLGROUP'}; ...
    'dXPMDHID',	{11, 'ASLGROUP'}; ...
    'dXasl',    {}};
ASLRIGHT = { ...
    'dXkbHID',  {'f', 'ASLGROUP'}; ...
    'dXPMDHID',	{9, 'ASLGROUP'}; ...
    'dXasl',    {}};
ASL = { ...
    'dXkbHID',  {['f';'j'], 'ASLUNGROUP', true}; ...
    'dXPMDHID', {[9;11], 'ASLUNGROUP', true}; ...
    'dXasl',    {}};

% correct response depends on random stimulus
%   for dXlr, 0=left, 1=right
lcon = {'jump', {'dXlr', 1, 'value'}, [0 1], {'correct'; 'incorrect'}};
rcon = {'jump', {'dXlr', 1, 'value'}, [0 1], {'incorrect'; 'correct'}};

SP = @rPlay;
GS = @rGraphicsShow;
SD = @biasSetDirections;
VU = @rVarUpdate;
Gr = @rGroup;
Se = @rSet;

CT = @centerTargetOnFixation;
ctf = {2, 300};

nxt = 'next';
err = 'error';
if showText
    fp = {'dXtarget', 1, 'dXtext'};
else
    fp = {'dXtarget', 1};
end

bp = 'dXbeep';
sd = 'dXsound';
stimOn = {'dXdots'};
stimOff = {{}, 'dXdots', fp{:}};

asl = {'gXASLCalibrate'};

% THE STATE DINNER. Careful -- this MUST be a double cellery.
%
%   You know those guitars that are like *double* guitars?
%
%   name        fun args        jump    wait    repsDrawQuery   cond
arg_dXstate = {{ ...
    'indicate', GS, fp,         nxt,    0,      0,  3,  0,      {}; ...
    'acquire',  {}, {},         aqJ,    aqW,    0,  0   acquire,{}; ...
    'hold',     {}, {},         nxt,    350,    0,  0,  hold,   {}; ...
    'recenter', CT, ctf,        nxt,	0,      0,  0,  1,      {}; ...
    'settle',   {}, {},         nxt,	150,    0,  0,  settle, {}; ...
    ...
    'tone1',	SP, {bp,1},     nxt,    100,	0,  0,  1,      {}; ...
    'nextDir',	SD, task,       nxt,    200,    0,  0,  1,      {}; ...
    'nextCoh',	VU, ptrs,       nxt,    200,    0,  0,  1,      {}; ...
    'drawStim',	GS, stimOn,     nxt,    400,    0,  0,  1,      {}; ...
    'tone2',	SP, {bp,2},     nxt,    100,	0,  0,  fixate,	{}; ...
    'showStim', {}, {},         nxt,    show,   0,  1,  1,      {}; ...
    'hideStim', GS, stimOff,	nxt,    0,      0,  3,  1,      {}; ...
    ...
    'respond',  {}, {},         err,    post,   0,  0,  respond,{}; ...
    'left',     {}, {},         err,    hang,	0,  0,  left,   lcon; ...
    'right',    {}, {},         err,    hang,	0,  0,  right,  rcon; ...
    'both',     {}, {},         err,    0,      0,  0,  0,      {}; ...
    ...
    'ASLLEFT',	{}, {},         'end',  500,	0,  0,  ASLLEFT,{}; ...
    'ASLRIGHT',	{}, {},         'end',  500,	0,  0,  ASLRIGHT,{}; ...
    'ASLGROUP', Gr, asl,        'next', 0,      0,  0,  0,      {}; ...
    'ASL',      {}, {},         'next', 2e6,    0,  3,  ASL,	{}; ...
    'ASLUNGROUP',Gr,task,       'end',  0,      0,  0,  0,      {}; ...
    ...
    'correct',  SP, {sd,1},     'end',  500,	0,  0,  0,      {}; ...
    'incorrect',SP, {sd,2},     'end',  500,	0,  0,  0,      {}; ...
    'error',    SP, {sd,3},     nxt,    500,	0,  5,  0,      {}; ...
    'end',      {}, {},         'x',    0,      0,  5,  0,      {}; ...
    }};
sz = size(arg_dXstate{1}, 1);

tony = {'current', true, true, false};
states_ = {'dXstate', sz, tony, arg_dXstate};